package com.gitee.wsl.transform.validator.func


import arrow.core.flatMap
import com.gitee.wsl.transform.validator.ValidatorWithTransform


fun <I, O, E : E2, I2 : I, O2, E2> ValidatorWithTransform<I, O, E>.flatMap(f: (O) -> ValidatorWithTransform<I2, O2, E2>): ValidatorWithTransform<I2, O2, E2> =
    ValidatorWithTransform { i ->
        validate(i).flatMap { o -> f(o).validate(i) }
    }

/**
 * Returns a [Parser] that maps the result of this parser by invoking the given function [f]
 * when the underlying parser returns a valid instance.
 *
 * This function performs no validation. It simply modifies the output from the underlying parser.
 *
 * @param f the function invoked to map the output of the underlying parser.
 *
 * @return a parser which returns the modified result of this parser.
 */
fun <I, A, B, E> ValidatorWithTransform<I, A, E>.map(f: (A) -> B): ValidatorWithTransform<I, B, E> =
    ValidatorWithTransform { this@map.validate(it).map(f) }

/**
 * Maps a [Parser] that returns A? to a parser that returns B? by applying a function [f]
 * if the output is not null. If the output of the underlying parser is null, then null is
 * returned.
 *
 * @param f the function invoked to map the non-null output of the underlying parser.
 *
 * @return a parser which returns the modified result of this parser.
 */
fun <I, A, B, E> ValidatorWithTransform<I, A?, E>.mapIfNotNull(f: (A) -> B): ValidatorWithTransform<I, B?, E> =
    ValidatorWithTransform { input -> this@mapIfNotNull.validate(input).map { if (it == null) null else f(it) } }
